/*
 * @Author James Metting
 */


import javax.media.opengl.*;

import com.sun.opengl.util.*;
import com.sun.opengl.util.j2d.TextRenderer;

import java.applet.*;
import java.awt.*;

import javax.swing.*;
import javax.media.opengl.GL;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.GLU;
import java.awt.event.*;


public class PuzzleApplet extends JApplet implements GLEventListener, KeyListener, MouseListener
{
        static GLCanvas canvas;
        PuzzleColor backColor;
        PuzzlePiece[] pieces;
        int pieceSize;
        static boolean hasSelection;
        PuzzlePiece selected;
        float index = 0;
        FPSAnimator animator;
        TextRenderer[] renderer;
        Color textColor = new Color(0,0,0);;
        int[] order;// tells the order in which the pieces should be displayed
        int coolColor;
    LoadFile fileLoader;
    String[] load = {"LOAD"};

        public void init()
     {
                coolColor =0;

         canvas = new GLCanvas();
         this.add(canvas);
         int canvasWidth = 700;
                int canvasHeight = 700;
                Dimension dimension = new Dimension(canvasWidth, canvasHeight);
                canvas.setSize(dimension);
                this.setSize(dimension);
                canvas.addGLEventListener(this);
            canvas.addKeyListener(this);
            canvas.addMouseListener(this);
            animator = new FPSAnimator(canvas, 50); // set animator and frame rate
            fileLoader = new LoadFile();
     }
     //important for calculating piece positions
     public static int getYval()
     {
         return canvas.getHeight();
     }
     public static int getXval()
     {
         return canvas.getWidth();
     }
     /**
      * Starts the applet and sets up the puzzle or resets the puzzle
      * may be useful as a button call later
      */
     public void start()
     {
         backColor = new PuzzleColor(1,1,1);
         pieces = new PuzzlePiece[1];
         pieces = fileLoader.load();
         //pieces = PuzzleCreator.sample();
         order = new int[pieces.length];
         for (int i = 0;i<order.length;i++)
         {
                 order[i]=i;//initializes the order to be same as index
         }
         renderer = new TextRenderer[4];


         animator.start();//important for animating


     }
     public void stop()
     {
     }


     public void paint(Graphics g)
     {

     }
     //GLEventListener methods
     //important for GL
     public void init(GLAutoDrawable drawable)
     {

     }
     public void displayChanged(GLAutoDrawable drawable,boolean bool1,boolean bool2)
     {}
     public void display(GLAutoDrawable drawable)
     {
        GL gl = drawable.getGL();
        gl.glClearColor(0, 0, 0, 1);
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);
        gl.glColor3d(1, 1, 1);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();


        if (renderer[0] ==null)
        {

                Font font;
            Color color;
            font = new Font("Comic Sans MS",Font.PLAIN,50);

                renderer[0] = new TextRenderer(font);
                renderer[0].setColor(textColor);

                font = new Font("ArialBlack",Font.BOLD,100);
                renderer[1] = new TextRenderer(font);
                renderer[1].setColor(textColor);

                font = new Font("Arial",Font.BOLD,75);
                renderer[2] = new TextRenderer(font);
                renderer[2].setColor(textColor);

                font = new Font("Times New Roman",Font.PLAIN,60);
                renderer[3] = new TextRenderer(font);
                renderer[3].setColor(textColor);
        }

        if(backColor!=null)
                displayBackground(drawable);
                //updates the piece thats moving for visual asthetics
        try{
                if(hasSelection)
                {
                         Point posit = canvas.getMousePosition();
                 selected.setLocation((int)posit.getX(),(int)posit.getY());
                }
        }catch(NullPointerException ne)
        {
                //System.out.println("OFF SCREEN");
        }
        if(selected!=null)
         {
                 selected.updateAttached();
         }
        if(pieces!=null)//startup null pointer issue (should be fixed now)
        {
                 for (int i = (pieces.length-1); i>=0; i--)
                 {
                         pieces[order[i]].display(drawable, backColor);
                         pieces[order[i]].setUpdated(false);
                         emitString(drawable,pieces[order[i]].text,
                                         (float)(pieces[order[i]].location.x+.02),
                                         (float)(pieces[order[i]].location.y+PuzzlePiece.size-.02),
                                         pieces[order[i]].getLevel());
                 }
        }
        //Load Button

        emitString(drawable,load,.75f,-.9f,1);
     }
     /**
      * displays the background as a square of a given color
      * @param drawable
      * @param backColor
      */
     public void displayBackground(GLAutoDrawable drawable)
        {
                GL gl = drawable.getGL();
                gl.glPushMatrix();
                gl.glColor3f(backColor.getRed(), backColor.getGreen(), backColor.getBlue());

                //SQUARE -draws the base square in the above color
                gl.glBegin( GL.GL_QUADS );
                gl.glVertex3f( -1,1, 1 );
                gl.glVertex3f( 1,1, 1 );
                gl.glVertex3f(1,-1, 1 );
                gl.glVertex3f( -1,-1,1 );
                //display text
                gl.glMatrixMode(GL.GL_MODELVIEW);
                //emitString(drawable,text, (float)(location.x+size-.05), (float)(location.y+.05));
                //PuzzleApplet.emitString(drawable,text, (float)(location.x+size-.05), (float)(location.y+.05));
                gl.glEnd();
                gl.glPopMatrix();
        }
     /**
      * reShape initializes all of the core components for displaying
      * images on the Canvas.
      */
     public void reshape(GLAutoDrawable drawable, int x, int y, int w,
             int h)
         {
                 GL gl = drawable.getGL();
                 gl.glViewport(x, y, w, h);
                 canvas.requestFocusInWindow();
         }
     /** Key processing callback method */
     public void keyPressed(KeyEvent e) {
         if ( e.getKeyCode() == KeyEvent.VK_ESCAPE ) {
             System.exit(0);
         }
         else if(e.getKeyCode()==KeyEvent.VK_L)
         {
                 PuzzlePiece[] piecesTemp=fileLoader.load();
                 if (piecesTemp!=null)
                 {
                         pieces = piecesTemp;
                 }
                 order = new int[pieces.length];
                 for (int i = 0;i<order.length;i++)
                 {
                         order[i]=i;//initializes the order to be same as index
                 }


         }
         else {
             System.out.println("Not processed key");
         }
         canvas.repaint();
     }

     /** Not used method, but needed to instanciate KeyListener */
     public void keyReleased(KeyEvent e)
     {
     }

     /** Not used method, but needed to instanciate KeyListener */
     public void keyTyped(KeyEvent e)
     {

     }
     //Invoked when the mouse button has been clicked (pressed and released) on a component.
     public void        mouseClicked(MouseEvent e)
     {
         //load button
         if(e.getX()>615&&e.getX()<692&&e.getY()>668&&e.getY()<690)
                 {
                 PuzzlePiece[] piecesTemp=fileLoader.load();
                 if (piecesTemp!=null)
                 {
                         pieces = piecesTemp;
                 }
                 order = new int[pieces.length];
                 for (int i = 0;i<order.length;i++)
                 {
                         order[i]=i;//initializes the order to be same as index
                 }
                 }
         hasSelection = false;
         for (int i = (pieces.length-1); i>=0; i--)
         {
                 pieces[order[i]].setUpdated(false);
         }
         PuzzlePiece sel = null;
         boolean hassel = false;
                        for (int i = 0; i<pieces.length &&!hassel;i++)
                        {
                                if(pieces[order[i]].isMovable(e.getX(), e.getY()))
                                {
                                        sel = pieces[order[i]];
                                        hassel = true;
                                        swapOrder(i);
                                }
                        }
         if(e.getButton()==MouseEvent.BUTTON1)
         {
                 if(sel!=null)
                         sel.rotateCounter();

         }
         else if(e.getButton()==MouseEvent.BUTTON3)
         {
                 if(sel!=null)
                         sel.rotateClock();
         }
     }
     //   Invoked when the mouse enters a component.
        public void     mouseEntered(MouseEvent e)
        {
        }
        //      Invoked when the mouse exits a component.
        public void     mouseExited(MouseEvent e)
        {
        }
        //      Invoked when a mouse button has been pressed on a component.
        public void     mousePressed(MouseEvent e)
        {
                hasSelection = false;
                for (int i = 0; i<pieces.length &&!hasSelection;i++)
                {
                        if(pieces[order[i]].isMovable(e.getX(), e.getY()))
                        {
                                selected = pieces[order[i]];
                                hasSelection = true;
                                swapOrder(i);
                        }
                }

        }
//      Invoked when a mouse button has been pressed on a component.
        //check proximity of two pieces HERE!!!!
        public void     mouseReleased(MouseEvent e)
        {
                //System.out.println("RELEASED"+e.getX()+e.getY());
                if(hasSelection)
                {
                        selected.setLocation(e.getX(),e.getY());
                        selected.checkNeighbor();
                        hasSelection=false;
                }
        }
        /**
     * String creation class, outputs a String onto the
     * board in the specified position
     * tx,ty positions
     * @param s
     * @param tx
     * @param ty
     */
        private void emitString(GLAutoDrawable drawable, String[] text, float tx, float ty,int textLevel)
        {
                double distance=.1;
                switch (textLevel)
                {
                case 1:distance = .065;break;
                case 2:distance = .048;break;
                case 3:distance = .03;break;
                }
        renderer[textLevel].begin3DRendering();
                for (int i = 0; i<text.length;i++)
           {
                        ty -= distance;
                        renderer[textLevel].draw3D(text[i],tx,ty,-1,.0008f);
           }
        renderer[textLevel].end3DRendering();

        }
        /**
         * puts index in the front of the order and moves everything up one
         * @param index
         */
        private void swapOrder(int index)
        {
                int temp = order[index];//holds value for the front
                for (int i = index; i >=1;i--)
                {
                        order[i] = order[i-1];
                }
                order[0] =temp;
        }

}
